﻿using Autofac;
using CSRedis;
using Microsoft.IdentityModel.Tokens;
using SH.Common;
using SH.Common.CommonReturn;
using SH.Multitenant.Application.IServices.IPermission;
using SH.Multitenant.Domain.RBAC;
using SH.Multitenant.Infrastructure.IRepository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace SH.Multitenant.Application.Services
{
    public class PermissionServices : BaseServices<Permission>, IPermissionServices
    {
        private readonly IPermissionRepository _permissionRepository;
        private readonly IEmpRoleRepository _empRoleRepository;
        private readonly IRolePermissionRepository _rolePermissionRepository;
        private readonly CSRedisClient _redis = AppService.AutofacContainer.Resolve<CSRedisClient>();

        public PermissionServices(IPermissionRepository permissionRepository, IEmpRoleRepository empRoleRepository, IRolePermissionRepository rolePermissionRepository) : base(permissionRepository)
        {
            _permissionRepository = permissionRepository;
            _empRoleRepository = empRoleRepository;
            _rolePermissionRepository = rolePermissionRepository;
        }
        #region private
        //获取子菜单
        private List<MenuDTO> GetMenuDTOs(List<MenuDTO> list, string? parentId)
        {
            var menuList = (from a in list
                            where a.ParentId == parentId
                            select new MenuDTO
                            {
                                PId = a.PId,
                                PName = a.PName,
                                ParentId = a.ParentId,
                                Path = a.Path,
                                Icon = a.Icon,
                                Children = GetMenuDTOs(list, a.PId)
                            }).ToList();
            var result = menuList.Any() ? menuList : null;
            return result;
        }

        #endregion
        //根据用户获取菜单权限
        public List<MenuDTO> GetMenusByEId(string? empId, string? parentId = "Top")
        {
            //var result = _redis.Get<List<MenuDTO>>("currentEmpMenuPermissions");
            //if (result == null || !result.Any())
            //{

            //string tenantId = _redis.Get<string>("tenantId");
            //var result = _redis.HGet<List<MenuDTO>>("currentUserMenus", tenantId + empId + parentId);
            //if (result != null && result.Count() > 0)
            //{
            //    return result;
            //}
            var empRole = _empRoleRepository.All;
            var rolePermission = _rolePermissionRepository.All;
            var permission = _permissionRepository.All;
            var list = empRole.LeftJoin<Role_Permission>(rolePermission, (a, b) => a.RoleId == b.RoleId).LeftJoin<Permission>(permission, (a, b, c) => b.PId == c.PId).Where((a, b, c) => a.EmpId == empId).Select((a, b, c) => new MenuDTO
            {
                PId = c.PId,
                PName = c.PName,
                ParentId = c.ParentId,
                Path = c.Path,
                Icon = c.Icon,
                Children = null,
            }).ToList();
            var result = GetMenuDTOs(list, parentId);
            //_redis.HSet("currentUserMenus", empId + parentId, result);
            //_redis.Expire("currentUserMenus", 120);
            //var random = new Random();
            //var randomNumber = random.Next(3, 5);
            //_redis.Set("currentEmpMenuPermissions", result, randomNumber);
            //}
            return result;
        }
        //根据地址获取当前用户当前地址的按钮权限
        public async Task<List<Permission>> GetButtonPermissionsByPathAsync(string? empId, string? path)
        {
            //获取对应路由的权限
            var parentPermission = await _permissionRepository.All.FirstAsync(x => x.Path == path);
            if (parentPermission != null)
            {
                var list = await _empRoleRepository.All.LeftJoin<Role_Permission>(_rolePermissionRepository.All, (a, b) => a.RoleId == b.RoleId).LeftJoin<Permission>(_permissionRepository.All, (a, b, c) => b.PId == c.PId).Where((a, b, c) => (string.IsNullOrEmpty(a.EmpId) || a.EmpId == empId) && c.ParentId == parentPermission.PId).Select((a, b, c) => new Permission
                {
                    PId = c.PId,
                    PName = c.PName,
                    ParentId = c.ParentId,
                    Path = c.Path,
                    Icon = c.Icon,
                }).ToListAsync();
                return list;
            }
            return new List<Permission>();
        }
        //获取所有的权限树形
        public List<MenuDTO> GetAllMenus()
        {
            string tenantId = _redis.Get<string>("tenantId");
            var list = _redis.HGet<List<MenuDTO>>("allMenus", tenantId);
            if (list != null && list.Count() > 0)
            {
                return list;
            }
            var queryList = _permissionRepository.All.Select(x => new MenuDTO
            {
                PId = x.PId,
                PName = x.PName,
                ParentId = x.ParentId,
                Path = x.Path,
                Icon = x.Icon,
                Children = null,
            }).ToList();
            List<string> parentIds = _permissionRepository.All.Where(x => !x.ParentId.StartsWith("M%")).Distinct().Select(x => x.ParentId).ToList();
            list = new List<MenuDTO>();
            foreach (var item in parentIds)
            {
                list.AddRange(GetMenuDTOs(queryList, item));
            }
            _redis.HSet("allMenus", tenantId, list);
            _redis.Expire("allMenus", 120);
            return list;
        }
        //根据角色id获取角色权限
        public List<Permission> GetPermissionsByRoleId(int roleId)
        {
            string tenantId = _redis.Get<string>("tenantId");
            var list = _redis.HGet<List<Permission>>("rolePermissionList", tenantId + roleId.ToString());
            if (list != null && list.Count() > 0)
            {
                return list;
            }
            list = _rolePermissionRepository.All
                .LeftJoin<Permission>(_permissionRepository.All, (a, b) => a.PId == b.PId).Where((a, b) => a.RoleId == roleId).Select((a, b) => new Permission
                {
                    PId = a.PId,
                    PName = b.PName,
                    ParentId = b.ParentId,
                    Path = b.Path,
                    Icon = b.Icon,
                }).ToList();
            _redis.HSet("rolePermissionList", tenantId + roleId.ToString(), list);
            _redis.Expire("rolePermissionList", 120);
            return list;
        }
        //修改角色权限
        public int UpdRolePermissions(int roleId, string? pIds)
        {
            using var tran = _permissionRepository.MultitenantUseTran();
            try
            {
                //删除所有该角色权限
                List<Role_Permission> list = _rolePermissionRepository.All.Where(x => x.RoleId == roleId).ToList();
                _rolePermissionRepository.BatchDelete(list);
                //给该角色添加权限
                List<Role_Permission> rps = new List<Role_Permission>();
                //判断是否为空
                if (string.IsNullOrEmpty(pIds))
                {
                    _rolePermissionRepository.MultitenantCommit();
                    return 1;
                }
                var array = pIds.Split(',');
                foreach (var item in array)
                {
                    rps.Add(new Role_Permission
                    {
                        RoleId = roleId,
                        PId = item,
                        //TenantId = _redis.Get<string>("tenantId")
                    });
                }
                var result = _rolePermissionRepository.BatchInsert(rps);
                //删除该key
                //_redis.HDel("currentUserMenus", $"{roleId}Top");
                //_redis.HDel("rolePermissionList", roleId.ToString());
                tran.CommitTran();
                return result;
            }
            catch (Exception)
            {
                tran.RollbackTran();
                throw;
            }
        }
        //根据父级编号获取权限列表
        public async Task<List<string>> GetSubPermissionsByParentId(string? parentId)
        {
            var list = await _permissionRepository.All.Where(x => x.ParentId == parentId).ToListAsync();
            var pIds = list.Select(x => x.PId).ToList();
            return pIds;
        }

        //根据权限编号获取父级编号
        public async Task<string> GetParentIdByPId(string? pId)
        {
            var permission = await _permissionRepository.All.FirstAsync(x => x.PId == pId);
            return permission.ParentId;
        }

        //判断该用户是否有资源对应的权限
        public async Task<bool> DeterminesWhetherHasThisPermissionAsync(string empId, string path)
        {
            //获取该用户的角色
            var role = await _empRoleRepository.GetModelByConditionAsync(x => x.EmpId == empId && x.TenantId == _redis.Get<string>("tenantId"));
            int roleId = 0;
            if (role != null)
            {
                roleId = role.RoleId;
            }
            var list = GetPermissionsByRoleId(roleId);
            if (list == null)
            {
                return false;
            }
            bool isHas = false;
            if (path == "/index/general") return true;
            foreach (var item in list)
            {
                if (item.Path == path)
                {
                    isHas = true;
                    break;
                }
            }
            return isHas;
        }
        //多条件分页获取权限列表
        public async Task<ApiPaging<List<Permission>>> GetCondtionPagingPermissionList(string? pName, int pageSize, int pageIndex)
        {
            Expression<Func<Permission, bool>> predicate = x => true;
            if (!string.IsNullOrEmpty(pName))
            {
                predicate = x => x.PName.Contains(pName);
            }
            var apiPaging = await _permissionRepository.PageQueryAsync(_permissionRepository.All, predicate, "PId desc", pageSize, pageIndex);
            return apiPaging;
        }
    }
}
